﻿using Microsoft.AspNetCore.Connections;
using System.Buffers;
using System.IO.Pipelines;

namespace sgf.server
{
    public sealed class TcpChannel : NetChannel
    {
        private ConnectionContext context { get; set; }
        private PipeReader reader { get; }
        private PipeWriter writer { get; }


        private readonly SemaphoreSlim _sendSemaphore = new(0);

        private readonly Action<long, byte[]> _onMessage;

        // private long lastReviceTime;
        // private int lastOrder;
        // const int MAX_RECV_SIZE = 1024 * 1024 * 5;

        /// 从客户端接收的包大小最大值（单位：字节 5M）
        public TcpChannel(ConnectionContext context, Action<long, byte[]> onMessage)
        {
            _onMessage = onMessage;
            this.context = context;
            reader = context.Transport.Input;
            writer = context.Transport.Output;
            remoteAddress = context.RemoteEndPoint?.ToString() ?? "";
        }

        public override async Task StartAsync()
        {
            var reading = ReadAsync();
            var writing = SendAsync();
            await Task.WhenAll(reading, writing);
            Close();
        }

        private async Task ReadAsync()
        {
            try
            {
                var token = context.ConnectionClosed;
                while (!token.IsCancellationRequested)
                {
                    var result = await reader.ReadAsync(token);
                    try
                    {
                        _onMessage?.Invoke(GetData<long>("sessionId"), result.Buffer.ToArray());
                    }
                    catch (Exception e)
                    {
                        LogMgr.Error($"onMessage Error {e.Message}");
                        break;
                    }
                    finally
                    {
                        reader.AdvanceTo(result.Buffer.Start, result.Buffer.End);
                    }

                    // var buffer = result.Buffer;
                    // try
                    // {
                    //     if (result.IsCanceled)
                    //         break;
                    //
                    //     var count = 0;
                    //     while (TryParseMessage(ref buffer, out var msg))
                    //     {
                    //         await onMessage?.Invoke(msg);
                    //         if (++count <= 20) continue;
                    //         await Task.Yield();
                    //         count = 0;
                    //     }
                    //
                    //     if (result.IsCompleted)
                    //     {
                    //         break;
                    //     }
                    // }
                    // catch (Exception e)
                    // {
                    //     LogMgr.Error("", e);
                    //     break;
                    // }
                    // finally
                    // {
                    //     Reader.AdvanceTo(buffer.Start, buffer.End);
                    // }
                }
            }
            catch (Exception e)
            {
                LogMgr.Error("TcpChannel ReadAsync error: " + e.Message);
            }
            finally
            {
                await reader.CompleteAsync();
            }
        }

        private async Task SendAsync()
        {
            var token = context.ConnectionClosed;
            try
            {
                while (!token.IsCancellationRequested)
                {
                    try
                    {
                        await _sendSemaphore.WaitAsync(token);
                        var flush = await writer.FlushAsync(token);
                        if (flush.IsCompleted || flush.IsCanceled)
                            break;
                    }
                    catch
                    {
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                LogMgr.Error("TcpChannel SendAsync error: " + e.Message);
            }
            finally
            {
                await writer.CompleteAsync();
            }
        }
        //
        // protected virtual bool TryParseMessage(ref ReadOnlySequence<byte> input, out Message msg)
        // {
        //     msg = default;
        //     var bufEnd = input.End;
        //     var reader = new SequenceReader<byte>(input);
        //
        //     if (!reader.TryReadBigEndian(out int msgLen))
        //     {
        //         return false;
        //     }
        //
        //     if (!CheckMsgLen(msgLen))
        //     {
        //         throw new Exception("消息长度异常");
        //     }
        //
        //     if (reader.Remaining < msgLen - 4)
        //     {
        //         return false;
        //     }
        //
        //     var payload = input.Slice(reader.Position, msgLen - 4);
        //
        //
        //     reader.TryReadBigEndian(out long time);
        //     if (!CheckTime(time))
        //     {
        //         throw new Exception("消息接收时间错乱");
        //     }
        //
        //     reader.TryReadBigEndian(out int order);
        //     if (!CheckMagicNumber(order, msgLen))
        //     {
        //         throw new Exception("消息order错乱");
        //     }
        //
        //     reader.TryReadBigEndian(out int msgId);
        //
        //     // var msgType = HotfixMgr.GetMsgType(msgId);
        //     // if (msgType == null)
        //     // {
        //     //     LOGGER.Error("消息ID:{} 找不到对应的Msg.", msgId);
        //     // }
        //     // else
        //     // {
        //     //     var message = Serializer.Deserialize<Message>(payload.Slice(16));
        //     //     if (message.MsgId != msgId)
        //     //     {
        //     //         throw new Exception($"解析消息错误，注册消息id和消息无法对应.real:{message.MsgId}, register:{msgId}");
        //     //     }
        //     //
        //     //     msg = message;
        //     // }
        //
        //     input = input.Slice(input.GetPosition(msgLen));
        //     return true;
        // }

        // public bool CheckMagicNumber(int order, int msgLen)
        // {
        //     order ^= 0x1234 << 8;
        //     order ^= msgLen;
        //
        //     if (lastOrder != 0 && order != lastOrder + 1)
        //     {
        //         LogMgr.Error("包序列出错, order=" + order + ", lastOrder=" + lastOrder);
        //         return false;
        //     }
        //
        //     lastOrder = order;
        //     return true;
        // }

        // /// <summary>
        // /// 检查消息长度是否合法
        // /// </summary>
        // /// <param name="msgLen"></param>
        // /// <returns></returns>
        // public bool CheckMsgLen(int msgLen)
        // {
        //     //消息长度+时间戳+magic+消息id+数据
        //     //4 + 8 + 4 + 4 + data
        //     if (msgLen <= 16) //(消息长度已经被读取)
        //     {
        //         LogMgr.Error("从客户端接收的包大小异常:" + msgLen + ":至少16个字节");
        //         return false;
        //     }
        //     else if (msgLen > MAX_RECV_SIZE)
        //     {
        //         LogMgr.Error("从客户端接收的包大小超过限制：" + msgLen + "字节，最大值：" + MAX_RECV_SIZE / 1024 + "字节");
        //         return false;
        //     }
        //
        //     return true;
        // }

        // /// <summary>
        // /// 时间戳检查(可以防止客户端游戏过程中修改时间)
        // /// </summary>
        // /// <param name="context"></param>
        // /// <param name="time"></param>
        // /// <returns></returns>
        // public bool CheckTime(long time)
        // {
        //     if (lastReviceTime > time)
        //     {
        //         LogMgr.Error("时间戳出错，time=" + time + ", lastTime=" + lastReviceTime);
        //         return false;
        //     }
        //
        //     lastReviceTime = time;
        //     return true;
        // }

        public override void Write(byte[] bytes)
        {
            if (IsClose()) return;


            lock (writer)
            {
                writer.Write(bytes);
            }

            if (_sendSemaphore.CurrentCount == 0)
                _sendSemaphore.Release();
        }

        protected override void Close()
        {
            if (IsClose())
                return;

            lock (this)
            {
                try
                {
                    _sendSemaphore.Release(short.MaxValue);
                    _sendSemaphore.Dispose();
                }
                catch
                {
                    // ignored
                }

                try
                {
                    context.Abort();
                }
                catch
                {
                    // ignored
                }

                try
                {
                    context.DisposeAsync();
                }
                catch
                {
                    // ignored
                }

                context = null;
            }
        }

        public override bool IsClose()
        {
            return context.ConnectionClosed.IsCancellationRequested;
        }
    }
}